package com.woniuxy.filter;

import com.alibaba.fastjson2.JSON;
import com.woniuxy.util.JwtUtil;
import com.woniuxy.util.ResponseData;
import com.woniuxy.util.ResponseEnum;
import lombok.SneakyThrows;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.util.ContentCachingRequestWrapper;

import javax.annotation.Resource;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.TimeUnit;

/**
 * @program: bookstore
 * @description:
 * @create: 2024-10-08 16:31
 **/
//当有多个过滤器时，以下注解执行顺序不好指定
//@WebFilter("/*")
@Component
//在springboot中更推荐用配置类的形式
public class LoginFilter  implements Filter  {
    @Resource
    private StringRedisTemplate stringRedisTemplate;

    //未登录的过滤器
    //1实现filter接口
    //2重写dofilter方法
    //3注册自定义过滤器
    @SneakyThrows//lombok注解式抛异常
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("now join in filter");

        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;

        // 使用 ContentCachingRequestWrapper 来包装请求体
        ContentCachingRequestWrapper wrappedRequest = new ContentCachingRequestWrapper(request);
        // 判断请求是否携带jwt (从请求头中获取)

        String requestURI = request.getRequestURI();  // 获取到controller层路径 /user/login

        if (!matchWhiteURI(requestURI)) {

            response.setContentType("application/json;charset=utf-8");

            // 判断请求头中是否携带 JWT
            String headerJWT = wrappedRequest.getHeader("authorization");
            if (headerJWT == null) {
                response.getWriter().print(JSON.toJSONString(new ResponseData<>().fail(ResponseEnum.NO_LOGIN)));
                return; // 拦截请求
            }

            // 解密JWT
            if (!JwtUtil.decode(headerJWT)) {
                response.setContentType("application/json;charset=utf-8");
                response.getWriter().print(JSON.toJSONString(new ResponseData<>().fail(ResponseEnum.LOGIN_ERROR)));
                return; // 拦截请求
            }

            // 判断前端 JWT 和 Redis 中的 JWT 是否一致
            Map userMap = JwtUtil.getUserMap(headerJWT);
            Long id = (Long) userMap.get("id");
            String redisJwt = stringRedisTemplate.opsForValue().get("jwt:" + id);

            if (!headerJWT.equals(redisJwt)) {
                response.setContentType("application/json;charset=utf-8");
                response.getWriter().print(JSON.toJSONString(new ResponseData<>().fail(ResponseEnum.NO_LOGIN)));
                return; // 拦截请求
            }

            // 给 JWT 续期,加随机数解决缓存雪崩问题
            stringRedisTemplate.expire("jwt:" + id, 60 + new Random().nextInt(15), TimeUnit.MINUTES);

            // 读取请求体（此时请求体被缓存）
            String body = new String(wrappedRequest.getContentAsByteArray(), wrappedRequest.getCharacterEncoding());
            // 如果需要，可以在这里进一步处理请求体的内容
//            System.out.println("Request Body: " + body);
        }

        // 放行请求，继续执行后续过滤器或请求
        // 放行请求，传递 wrappedRequest 而不是原始 request
        filterChain.doFilter(wrappedRequest, servletResponse);
    }

    @Override
    public void destroy() {
        // 销毁
    }

    // 自定义的白名单路径匹配方法
    private boolean matchWhiteURI(String uri) {
        // 根据需求判断哪些路径不需要JWT验证
        return uri.startsWith("/powerUser/login") || uri.startsWith("/powerUser/imgLoad1");
    }
}